;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; lcd.inc is een include file voor het gebruik van het lcd scherm op het
; ADuC800 bord. Het bord wordt gebruikt met een 1*16 of een 2*16 karakter
; display. De basisroutines zijn bruikbaar voor alle types schermen (de
; gebruiker moet dan wel zelf wakker liggen over cursorrouting).
; De hogere routines gaan er van uit dat we een 2*16 karakter display gebruiken.
; Parameters worden doorgegeven via de accu, b register, dptr of r0.
; De routines gebruiken geen registers. Alle timing wordt automatisch aangepast
; aan de waarden in het pllcon register. De routines zijn geoptimaliseerd naar
; de aansluitingen op het ADuC800 bord.
;
; De 2 overblijvende klemmen van poort 0 (p0.0 en p0.1) worden niet aangepast.
;
; GESCHREVEN OP 02/1994 DOOR MARC ROGGEMANS als lcd.drv
;      -aangepast door Roggemans Marc (MGM) op 11/2004 voor ADuC800 kaart als 
;       aduclcd0.inc
;      -aangepast door Roggemans Marc (MGM) op 11/11/2004
;       aduclcd1.inc
;             -00dh en 00ah worden door outchar verwerkt
;             -bij de init wordt het display anders opgestart
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

e             bit    p0.2                 ;enable
rs            bit    p0.3                 ;register select

lcdport       EQU    p0                   ;SELECTIE POORT 0

cleardisp     EQU    001H                 ;LEEG MAKEN VAN HET SCHERM
cursathom     EQU    002H                 ;CURSOR OP DE EERSTE PLAATS ZETTEN

entrymode     EQU    00000110B            ;CURSOR NAAR RECHTS, SCHERM VAST
displayon     EQU    00000001B            ;HOMEN EN CLEAR CURSOR
displayof     EQU    00001000B            ;DISPLAY OFF, CURSOR OFF
cursoroff     EQU    00001100B            ;DISPLAY ON ZONDER CURSOR
cursoronb     EQU    00001111B            ;CURSOR ON AND BLINK
cursoronn     EQU    00001110B            ;CURSOR ON NO BLINK
functions     EQU    00101000B            ;INTERFACE LENGTE EN KARAKTER FONT
cgram         EQU    01000000B            ;SELECTIE KARAKTER GENERATOR RAM
ddram         EQU    10000000B            ;SELECTIE DATA DISPLAY RAM

lcd00	equ		080h		;lcd lijn 0 char 0
lcd01	equ		081h
lcd02	equ		082h
lcd03	equ		083h
lcd04	equ		084h
lcd05	equ		085h
lcd06	equ		086h
lcd07	equ		087h
lcd08	equ		088h
lcd09	equ		089h
lcd0A	equ		08Ah
lcd0B	equ		08Bh
lcd0C	equ		08Ch
lcd0D	equ		08Dh
lcd0E	equ		08Eh
lcd0F	equ		08Fh

lcd10	equ		0C0h		;lcd lijn 1 char 0
lcd11	equ		0C1h
lcd12	equ		0C2h
lcd13	equ		0C3h
lcd14	equ		0C4h
lcd15	equ		0C5h
lcd16	equ		0C6h
lcd17	equ		0C7h
lcd18	equ		0C8h
lcd19	equ		0C9h
lcd1A	equ		0CAh
lcd1B	equ		0CBh
lcd1C	equ		0CCh
lcd1D	equ		0CDh
lcd1E	equ		0CEh
lcd1F	equ		0CFh

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; initlcd     zal het scherm resetten en initialiseren voor gebruik via een 4
; bit bus. De routine zet het scherm klaar voor normaal gebruik: ingave van
; links naar rechts zonder display shift, normale karakterfont. De kursor staat
; aan als een knipperend lijntje onderaan de regel. Het scherm is leeg.
;
; registergebruik: geen
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

initlcd:      push   acc           ;registers op stack plaatsen
              push   psw
              mov    lcdport,#003h ;poort in uitgangstoestand zetten
                                   ;let op:twee laagste bits worden
                                   ;niet gebruikt
              mov    a,#010h       ;bij opstarten meer dan 30ms wachten
initlcd1:     lcall  delay2ms
              djnz   acc,initlcd1
              mov    a,#00110000b  ;volgende drie schrijfbeurten zijn 
              lcall  outhnibc      ;een truuk om het display altijd opgestart
              lcall  delay2ms      ;te krijgen.
              mov    a,#00110000b
              lcall  outhnibc
              lcall  delay2ms
              mov    a,#00110000b
              lcall  outhnibc
              lcall  delay2ms
              mov    a,#00100000b  ;instellen 4 bit interface gebruiken
              lcall  outhnibc      ;hoge nibble naar het controleregister
              lcall  delay2ms      ;niet nodig volgens datasheet
              mov    a,#functions  ;4 bit interface, twee lijnen 5*8 dots
              lcall  outc          ;naar display
              lcall  delay2ms      ;is iets te lang volgens datasheet
              mov    a,#cursoronb  ;display on cursor on and blink
              lcall  outc
              lcall  delay2ms      ;ook deze delay is iets te lang
              mov    a,#displayon  ;clear display and home cursor
              lcall  outc
              lcall  delay2ms      ;deze wachttijd is bijna juist
              mov    a,#entrymode  ;display klaar zetten normaal gebruik
              lcall  outc
              lcall  delay2ms      ;wachten weer veel te lang
			  mov 	 a,#00ch	   ;clear schermpje
			  lcall	 outcharlcd
              mov    a,#cursoroff	   ;zet cursor af
              lcall  outcharlcd
              pop    psw           ;registers terug in orde zetten
              pop    acc
              ret                  ;einde van de initialisatie

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; outcharlcd  zal de ascii code in de accu naar het lcd scherm sturen. De codes
; lager dan 020h worden als controlekarakters bekeken met volgende acties:
;      00dh   =cursor in de home positie
;      00ch   =form feed    =scherm leeg maken en kursor op lacatie 000h
;      00ah   =cursor op tweede lijn plaatsen
;      001h   =cursor on blink
;      002h   =cursor on blink
;      003h   =cursor off
;      080h-0ffh     =cursor plaatsen op dit adres -80h
;
; de routine gebruikt geen registers
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; we gaan eerst na of het een ascii code betreft van een symbool. Als dat zo is,
; dan mag de data direct naar het dataregister van het scherm.
; Betreft een controle karakter, dan is een andere aanpak nodig (zie verder).

outcharlcd:   push   acc           ;registers op stack
              push   psw
              cjne   a,#080h,outcharlcd1  ;hogere codes zijn adressen
outcharlcd1:  jnc    outcharlcd9   ;als geen carry dan is de code een address
              cjne   a,#020h,outcharlcd2  ;hogere codes zijn ascii van symbolen
outcharlcd2:  jnc    outcharlcd8   ;als geen carry dan ascii code naar display

; de code in de accu is geen adres of geen geldige ascii code van een symbool.
; Het is dus een opdracht die we moeten uitvoeren.

              cjne   a,#00ch,outcharlcd3  ;geen form feed, dan jump
              mov    a,#cleardisp         ;scherm leegmaken
              lcall  outc                 ;naar controleregister
              sjmp   outcharlcde          ;afsluiten
              
outcharlcd3:  cjne   a,#001h,outcharlcd4  ;geen cursor on blink
              mov    a,#cursoronb         ;cursoron met blink
              lcall  outc
              sjmp   outcharlcde 

outcharlcd4:  cjne   a,#002h,outcharlcd5  ;geen cursor on no blink
              mov    a,#cursoronn         ;cursoron no blink
              lcall  outc
              sjmp   outcharlcde

outcharlcd5:  cjne   a,#003h,outcharlcd6  ;geen cursor off, dus afsluiten routine
              mov    a,#cursoroff         ;cursor uitschakelen
              lcall  outc
              sjmp   outcharlcde

outcharlcd6:  cjne   a,#00dh,outcharlcd7  ;geen cursor home zonder clear scherm
              mov    a,#cursathom         ;cursor in home positie
              lcall  outc
              sjmp   outcharlcde

outcharlcd7:  cjne   a,#00ah,outcharlcde  ;line feed gevraagd (zet cursor op
                                          ;tweede lijn
              mov    a,#0c0h
              lcall  outc
              sjmp   outcharlcde

; dit label wordt uitgevoerd als de code in de accumulator een geldige ascii code
; is. dit mag naar het data register.

outcharlcd8:  lcall  outd          ;klaar
              sjmp   outcharlcde   ;einde routine

; dit label wordt uitgevoerd als de code in de accu een adres is. Dit adres is
; eigenlijk 80 te groot. Dat komt echter goed uit als commando om een adrers te
; te schrijven.

outcharlcd9:  lcall  outc          ;klaar
outcharlcde:  pop    psw           ;registers herstellen
              pop    acc
              ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; outniblcd     zal de lage nibble omzetten in een ascii code en die afdrukken
; op het lcd scherm.
;
; de routine gebruikt geen registers
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

outniblcd:    push   acc           ;registers op stack zetten
              push   psw
              anl    a,#00fh       ;laagste 4 bits overhouden
              add    a,#030h       ;omvormen naar ascii codes 0-9
              cjne   a,#03ah,outniblcd1   ;als groter dan dit nog 7 bijtellen
outniblcd1:   jc     outniblcde    ;als carry dan omzetting klaar
              add    a,#007h       ;omvormen naar hoofdletter
outniblcde:   lcall  outd          ;naar het scherm
              pop    psw
              pop    acc
              ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; outbytelcd    zal de inhoud van de accu afdrukken op het lcd scherm.
;
; de routine gebruikt geen registers
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

outbytelcd:   push   acc           ;registers op de stack zetten
              push   psw
              swap   a             ;bitjes omruilen
              lcall  outniblcd
              swap   a             ;nog eens
              lcall  outniblcd
              pop    psw
              pop    acc
              ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; dispdptrlcd   zal de inhoud van de dptr afdrukken op het lcd scherm
;
; de routine gebruikt geen registers
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

dispdptrlcd:  push   acc           ;registers bewaren op stack
              push   psw
              mov    a,dph         ;hoge deel eerst naar het scherm
              lcall  outbytelcd
              mov    a,dpl         ;dan het lage deel
              lcall  outbytelcd
              pop    psw
              pop    acc
              ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; outmsgalcd  zal een string ascii codes op het scherm plaatsen. Het startadres
; van de string staat in de dptr. De string wordt afgesloten met een 000h.
; De routine gebruikt outcharlcd voor het sturen van karakters naar het LCD
; scherm. Positionnering van de cursor en cursorcontrole kan in de ascii string
; opgenomen worden met de pseudo ascii codes (zie outcharlcd).
;
; de routine gebruikt geen registers
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

outmsgalcd:   push   acc           ;registers op de stack
              push   psw
              push   dph           ;ook de data pointer
              push   dpl

;We lezen karakters uit code memory tot de 000h code gevonden wordt.

outmsgalcd1:  clr    a             ;waarde zit in onze weg
              movc   a,@a+dptr     ;waarde lezen
              jz     outmsgalcde   ;als 0 dan naar einde springen

; de code is niet 0 dus versturen met outchar

              lcall  outcharlcd    ;weg er mee
              inc    dptr          ;naar volgende ascii code wijzen
              ljmp   outmsgalcd1   ;lus sluiten

outmsgalcde:  pop    dpl           ;registers herstellen
              pop    dph
              pop    psw
              pop    acc
              ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; regtolcd    is een subroutine die de gegevens uit een register-buffer naar
; de lcd stuurt. De routtine gaat er van uit dat er op het scherm maar 16
; karakters per lijn zitten. De string ascii codes in het geheugen moet 32
; karakters bevatten. De routine verwacht in r0 het startadres van de buffer.
;
; de routine gebruikt geen registers
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


regtolcd:     push   acc           ;registers op de stack
              push   psw
              mov    a,r0
              push   acc
              mov    a,r1
              push   acc
              mov    r1,#000h      ;werkt als loopcounter
regtolcd1:    mov    a,@r0         ;karakter lezen
              lcall  outcharlcd    ;weg er mee
              inc    r0
              inc    r1
              cjne   r1,#016d,regtolcd1   ;als deze waarde 16 is moet een
                                          ;nieuwe lijn genomen worden
              mov    a,#(80h+40h)  ;dit is het eerste adres op de tweede lijn
              lcall  outcharlcd    ;hiermee plaatsen we de cursor op de juiste
                                   ;plaats
              
regtolcd2:    mov    a,@r0         ;karakter lezen
              lcall  outcharlcd    ;weg er mee
              inc    r0
              inc    r1
              cjne   r1,#032d,regtolcd2   ;als deze waarde 32 is stoppen
              pop    acc
              mov    r1,a
              pop    acc
              mov    r0,a
              pop    psw           ;registers herstellen
              pop    acc
              ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; outd is een routine die naar het data register van het display een
; volledige byte stuurt.
;
; De routine gebruikt geen registers.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

outd:         push   acc           ;registers op stack zetten
              push   psw
              lcall  outhnibd      ;hoogste vier bits verzenden
              lcall  delay60us     ;niet echt nodig
              swap   a             ;bitjes omruilen
              lcall  outhnibd      ;naar het scherm sturen
              lcall  delay60us     ;altijd goed
              pop    psw           ;registers terug herstellen
              pop    acc
              ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; outhnibd stuurt de hoge 4 bits van de accu naar het data register van het
; lcd scherm.
;
; de routine gebruikt geen registers.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

outhnibd:     push   acc           ;registers op stack plaatsen
              push   psw
              setb   rs            ;controle lijn in orde
              clr    e             ;deselectie display
              anl    a,#0f0h       ;4 meest beduidende bits afzonderen
              orl    a,#00bh       ;laagste 2 pinnen op 1 zetten en rs op 1
              mov    lcdport,a
              setb   e             ;display enabelen
              nop                  ;450ns is normaal gezien voldoende
              clr    e             ;display deselecteren
              pop    psw           ;registers herstellen
              pop    acc
              ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; outc is een routine die naar het controleregister van het display een
; volledige byte stuurt.
;
; De routine gebruikt geen registers.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

outc:         push   acc           ;registers op stack zetten
              push   psw
              lcall  outhnibc      ;hoogste vier bits verzenden
              lcall  delay2ms      ;niet echt nodig
              swap   a             ;bitjes omruilen
              lcall  outhnibc      ;naar het scherm sturen
              lcall  delay2ms      ;altijd goed voor traagste commando
              pop    psw           ;registers terug herstellen
              pop    acc
              ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; outhnibc stuurt de hoge 4 bits van de accu naar het controle register van het
; lcd scherm.
;
; de routine gebruikt geen registers.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

outhnibc:     push   acc           ;registers op stack plaatsen
              push   psw
              clr    rs            ;controle lijn in orde
              clr    e             ;deselectie display
              anl    a,#0f0h       ;4 meest beduidende bits afzonderen
              orl    a,#003h       ;laagste 2 pinnen op 1 zetten
              mov    lcdport,a
              setb   e             ;display enabelen
              nop                  ;450ns is normaal gezien voldoende
              clr    e             ;display deselecteren
              pop    psw           ;registers herstellen
              pop    acc
              ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; BUILD0 IS EEN ROUTINE DIE DE KARAKTERGENERATOR RAM ZAL LADEN MET HET
; BITPATROON VOOR 8 KARAKTERS. DE ROUTINE GEBRUIKT EEN BITMAP OP HET ADRES
; IN DPTR. DE TABEL WORDT AFGESLOTEN DOOR EEN BYTE MET BIT 7=1. DE ROUTINE
; GEBRUIKT DPTR, ACC, PSW EN ENKELE LCD.DRV ROUTINES. NA HET VULLEN VAN DE
; DATA RAM WORDT OPNIEUW ADRES 0 VAN DE DISPLAY RAM GESELECTEERD. ER WORDT GEEN
; DATA GESCHREVEN.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

BUILD:        MOV    A,#CGRAM      ;TOEGANG TOT KARAKTER GENERATOR RAM
BUILD1:       LCALL  OUTC          ;NAAR SCHERM VERSTUREN
BUILD3:       MOV    A,#000H       ;ACCU OP NUL ZETTEN
              MOVC   A,@A+DPTR     ;EERSTE CODE UIT TABEL LEZEN
              LCALL  OUTD          ;NAAR KARAKTER GENERATOR RAM STUREN
              JB     ACC.7,BUILD2  ;ALS BIT 1 DAN EINDE
              INC    DPTR          ;NAAR VOLGENDE LOKATIE WIJZEN
              SJMP   BUILD3
BUILD2:       MOV    A,#DDRAM      ;DATA DISPLAY RAM SELECTEREN
              LCALL  OUTC          ;NAAR KONTROLE REGISTER STUREN
              RET                  ;EINDE VAN DE ROUTINE

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Delay2ms is een vertragingsroutine van 2ms.
;
; De routine gebruikt geen registers.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

delay2ms:     push   acc           ;registers op de stack zetten
              push   psw
              mov    a,#032d       ;aantal keer 60us wachten
delay2ms1:    lcall  delay60us
              djnz   acc,delay2ms1
              pop    psw           ;registers herstellen
              pop    acc
              ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; delay routine van 60us.
; De tijdsvertraging klopt bij de hoogste kloksnelheid van de
; controller. Bij de traagste snelheid wordt de routine overgeslagen.
;
; de routine gebruikt geen registers.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

delay60us:    push   acc           ;registers op de stack plaatsen
              push   psw
              mov    a,pllcon      ;pllcon inlezen
              anl    a,#00000111b  ;beduidende bits overhouden

; hoe kleiner de waarde in de pllcon, hoe sneller de controller loopt.
; door wat bitbangen maken we er een bruikbare waarde van.

              cjne   a,#00000111,delay60us2  ;als traagste snelheid stoppen
              pop    acc           ;registers herstellen
              pop    psw
              ret

delay60us2:   mov    a,#25d        ;loopcounter laden
delay60us1:   djnz   acc,delay60us1  ;telkens twee cycles tijd verliezen
              pop    psw
              pop    acc
              ret
